﻿/*========================== 
 * @author 郑金泉
 * @desc 数据库类
 * ========================= */
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json.Linq;

using Obsidian;
using Obsidian.Config;
using Obsidian.Data.Sql.SqlSrvClient;

namespace Obsidian.Data.Sql
{

    /// <summary>
    /// 数据库类
    /// </summary>
    public class DataBase
    {

        /// <summary>
        /// 数据库信息缓存
        /// </summary>
        private static Hashtable dataBasesCache = Hashtable.Synchronized(new Hashtable());

        private Dictionary<string, DbTable> dictTables = new Dictionary<string, DbTable>();

        private string _version;
        /// <summary>
        /// 版本信息
        /// </summary>
        public string Version
        {
            get { return this._version; }
        }

        /// <summary>
        /// 获得数据库
        /// </summary>
        /// <param name="alias">数据库别名</param>
        /// <returns></returns>
        public static DataBase Get(string alias)
        {
            lock (dataBasesCache)
            {
                if (dataBasesCache.ContainsKey(alias))
                {
                    return (DataBase)dataBasesCache[alias];
                }
                else
                {
                    if (dataBasesCache.ContainsKey(alias))
                        return (DataBase)dataBasesCache[alias];
                    else
                    {
                        DataBase db = new DataBase(alias);
                        dataBasesCache.Add(alias, db);
                        return db;
                    }
                }
            }
        }

        public static DataBase Add(string alias, DataBaseType dbType, string connectionString, string version)
        {
            return Add(alias, null, dbType, connectionString, version);
        }

        public static DataBase Add(string alias, string owner, DataBaseType dbType, string connectionString, string version)
        {
            DataBase db;
            if (String.IsNullOrEmpty(owner))
                db = new DataBase(alias, dbType, connectionString, version);
            else
                db = new DataBase(alias, owner, dbType, connectionString, version);
            if (dataBasesCache.ContainsKey(alias))
            {
                throw new Exception("已存在别名" + alias + "的数据库信息");
            }
            dataBasesCache.Add(alias, db);
            return db;
        }

        private string _alias = null;
        /// <summary>
        /// 数据库别名
        /// </summary>
        public string Alias
        {
            get { return this._alias; }
        }

        private string _owner = null;
        public string Owner
        {
            get { return this._owner; }
        }

        private string _connectionString = null;
        /// <summary>
        /// 数据库连接字符串
        /// </summary>
        public string ConnectionString
        {
            get { return this._connectionString; }
            set { this._connectionString = value; }
        }

        private DataBaseType _type = DataBaseType.Unknown;
        /// <summary>
        /// 数据库类型
        /// </summary>
        public DataBaseType Type
        {
            get { return this._type; }
        }

        /// <summary>
        /// 构造方法
        /// </summary>
        /// <param name="alias">数据库别名</param>
        protected DataBase(string alias)
        {
            if (String.IsNullOrEmpty(alias))
                throw new Exception("数据库别名不能为空");
            this._alias = alias;

            DbConfig.DbInfo dbInfo = DbConfig.GetDbInfo(alias);

            if (dbInfo == null)
                throw new Exception("读取数据库连接配置\"" + alias + "\"错误!");

            string typeString = null;
            try
            {
                this._type = this.GetDataBaseType(dbInfo.Type);
            }
            catch
            {
                throw new Exception("读取数据库连接配置\"" + alias + "\"参数\"type\"错误!");
            }

            try
            {
                if (this._type == DataBaseType.OleDb)
                {
                    this._connectionString = MapPathConnectionString(dbInfo.ConnectionString);
                }
                else
                {
                    this._connectionString = dbInfo.ConnectionString;
                }
            }
            catch
            {
                throw new Exception("读取数据库连接配置\"" + alias + "\"参数\"connectionString\"错误!");
            }

            if (this._type == DataBaseType.Unknown)
                throw new Exception("未知数据库类型:\"" + typeString + "\"，数据库连接配置\"" + alias + "\"");

            if (this._type == DataBaseType.SqlServer)
            {
                SqlSrvExecutor executor = new SqlSrvExecutor(this.ConnectionString);
                string cmdText = "SELECT @@VERSION ";
                this._version = Convert.ToString(executor.ExecuteScalar(cmdText));
            }

            this._owner = dbInfo.Owner;

        }

        protected DataBase(string alias, DataBaseType dbType, string connectionString, string version)
        {
            this._alias = alias;
            this._type = dbType;

            if (this._type == DataBaseType.OleDb)
                this._connectionString = MapPathConnectionString(connectionString);
            else
                this._connectionString = connectionString;

            this._version = version;
        }

        protected DataBase(string alias, string owner, DataBaseType dbType, string connectionString, string version)
        {
            this._alias = alias;
            this._owner = owner;
            this._type = dbType;

            if (this._type == DataBaseType.OleDb)
                this._connectionString = MapPathConnectionString(connectionString);
            else
                this._connectionString = connectionString;

            this._version = version;
        }

        /// <summary>
        /// 获得数据库表
        /// </summary>
        /// <param name="tableName">表名称</param>
        /// <returns></returns>
        public DbTable GetTable(string tableName)
        {
            if (dictTables.ContainsKey(tableName))
            {
                return dictTables[tableName];
            }
            else
            {
                DbTable table;
                lock (dictTables)
                {
                    table = new DbTable(this, tableName);
                    if(!dictTables.ContainsKey(tableName))
                        dictTables.Add(tableName, table);
                }
                return table;
            }
        }
        

        public static string MapPathConnectionString(string connectionString)
        {
            StringBuilder sb = new StringBuilder();
            string[] strs = connectionString.Split(';');
            foreach (string str in strs)
            {
                if (String.IsNullOrEmpty(str))
                    continue;
                if (str.ToLower().IndexOf("data source") >= 0)
                {
                    try
                    {
                        int n = str.IndexOf("=");
                        string baseDir = AppDomain.CurrentDomain.BaseDirectory;
                        string path = baseDir + str.Substring(n + 1);
                        sb.Append(str.Substring(0, n + 1) + path);
                    }
                    catch (Exception ex)
                    {
                        sb.Append(str);
                    }
                }
                else
                {
                    sb.Append(str);
                }
                sb.Append(";");
            }
            connectionString = sb.ToString();
            return connectionString;
        }


        private DataBaseType GetDataBaseType(string typeString)
        {
            switch (typeString)
            {
                case "sqlsrv":
                    return DataBaseType.SqlServer;
                case "mysql":
                    return DataBaseType.MySql;
                case "oledb":
                    return DataBaseType.OleDb;
                default:
                    return DataBaseType.Unknown;
            }
        }


    }

    public enum DataBaseType
    {
        /// <summary>
        /// 未知数据库类型
        /// </summary>
        Unknown,
        SqlServer,
        MySql,
        OleDb
    }
}
